/**
 *
 */
package com.fita.scheduler.service.impl;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.JsonUtils;
import com.fita.entity.authority.RoleTemplate;
import com.fita.entity.dto.ehi.response.VehicleReservationCancleResponse;
import com.fita.entity.order.OrderEventType;
import com.fita.entity.order.OrderStatus;
import com.fita.entity.order.PayType;
import com.fita.entity.wallet.DistributionRewardRecordStatus;
import com.fita.scheduler.dao.*;
import com.fita.scheduler.entity.*;
import com.fita.scheduler.handler.EhiHandler;
import com.fita.scheduler.handler.MailHandler;
import com.fita.scheduler.service.OrderService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;

import javax.transaction.TransactionManager;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Guangli Yan
 *
 */
@Service("orderService")
public class OrderServiceImpl implements OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);

    @Autowired
    private DataSourceTransactionManager transactionManager;

    @Dao
    private OrderDao orderDao;

    @Dao
    private OrderEventDao orderEventDao;

    @Autowired
    private EhiHandler ehiHandler;

    @Dao
    private SupplierDao supplierDao;

    @Dao
    private DistributionRewardRecordDao distributionRewardRecordDao;

    @Dao
    private UserWalletDao userWalletDao;

    @Dao
    private AgentCompanyDao agentCompanyDao;

    @Autowired
    private MailHandler mailHandler;

    @Value("#{mail['finance.mail']}")
    private String financeEmail;

    private static String generateEmailText(Map<String, String> model) {

        String s = "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "</head>\n" +
                "<body style=\"margin: 0; padding: 0;\">\n" +
                "\n" +
                "<table align=\"center\" border=\"1\" cellpadding=\"0\" cellspacing=\"0\" width=\"600\" style=\"border-collapse: collapse;\">\n" +
                "\n" +
                "    <tr>\n" +
                "        <td> 订单号</td>\n" +
                "        <td> alamo订单号</td>\n" +
                "        <td> 标记支付时间</td>\n" +
                "        <td> 标记支付人员</td>\n" +
                "        <td> 标记支付金额</td>\n" +
                "    </tr>\n" +
                "\n" +
                "    ${slot}\n" +
                "\n" +
                "</table>\n" +
                "\n" +
                "</body>\n" +
                "</html>";

        return com.demo2do.core.utils.StringUtils.replacePlaceHolder(s, model);
    }

    /**
     * @return
     */
    public List<Order> listNeedCancelUnpaidOrder() {

        Date now = new Date();

        Date fiveDaysLater = DateUtils.addDays(now, 5);

        Date twoHoursAgo = DateUtils.addHours(now, -2);

        List<Order> orders = orderDao.list(Arrays.asList(OrderStatus.UNPAID.toString()),
                fiveDaysLater,
                PayType.PREPAY.toString(),
                twoHoursAgo);
        return orders;
    }

    /* (non-Javadoc)
     * @see com.fita.scheduler.service.OrderService#cancelOrder()
     */
    public void cancelUnpaidOrder(Order order) {


        if (StringUtils.isBlank(order.getAlamoCode())) {
            return;
        }
        logger.info("cancle upaid order start, id is [{}] and status is [{}], the create_time is [{}]", order.getId(), order.getStatus(), order.getCreateTime());

        orderDao.cancel(order.cancel());

        if (order.getDistributionRewardRecordId() != null) {

            distributionRewardRecordDao.cancel(order.getDistributionRewardRecordId());

            logger.info("cancel distribution reward record [{}] of order [{}]", order.getDistributionRewardRecordId(), order.getId());
        }
        OrderEvent orderEvent = new OrderEvent(order.getId(), -1L, new Date(), "未支付订单超时，系统自动取消", OrderEventType.CANCELBYSYSTEM.toString());

        orderEventDao.save(orderEvent);

        logger.info("cancle upaid order success, id is [{}] and status is [{}] ", order.getId(), order.getStatus());

        //24小时内的订单才需要去远程取消

        long now = new Date().getTime();
        long createTime = order.getCreateTime().getTime()+(60*1000*60*24);

        Date date = new Date(now);
        Date date1 = new Date(createTime);

        logger.info("#cancelUnpaidOrder() one now [{}] overCreateTime [{}]",date,date1);

        if(createTime> now){
            logger.info("#cancelUnpaidOrder() two now [{}] overCreateTime [{}]",date,date1);
            Map<String, Object> params = this.generateCancel(order);

            VehicleReservationCancleResponse vehicleReservationCancleResponse = ehiHandler.vehicleReservationCancle(params);

            String cancelStatus = vehicleReservationCancleResponse.getCancelStatus();

            logger.info("call vehicleReservationCancle api success, response status is [{}] ", cancelStatus);
        }

    }

    /* (non-Javadoc)
     * @see com.fita.scheduler.service.OrderService#consumeOrder()
     */
    public void consumeOrder() {

        Date now = new Date();

        Date threeDaysAgo = DateUtils.addDays(now, -3);

        List<Order> orders = orderDao.list(PayType.PREPAY.toString(), OrderStatus.PAID.toString(), threeDaysAgo);

        for (Order order : orders) {

            logger.trace("order [{}] consume. ", order.getId());

            orderDao.consume(order.consume());

            Long distributionRewardRecordId = order.getDistributionRewardRecordId();

            if (distributionRewardRecordId != null){
                DistributionRewardRecord distributionRewardRecord = distributionRewardRecordDao.load(distributionRewardRecordId);
                if (distributionRewardRecord.getStatus().isUnconsumed()){

                    UserWallet userWallet = userWalletDao.load(distributionRewardRecord.getTargetUserWalletId());

                    userWallet.consume(distributionRewardRecord.getAmount());

                    userWalletDao.consume(userWallet);

                    AgentCompany agentCompany = agentCompanyDao.load(userWallet.getAgentCompanyId());

                    agentCompany.addAgentCommission(distributionRewardRecord.getAmount());

                    agentCompanyDao.addAgentCommission(agentCompany);

                    distributionRewardRecord.consume(userWallet.getTotalAmount());

                    distributionRewardRecordDao.consume(distributionRewardRecord);

                    logger.trace("consume order distribution reward record  id [{}] success", distributionRewardRecordId);
                }
            }
            OrderEvent orderEvent = new OrderEvent(order.getId(), -1L, new Date(), "已支付预付订单，还车时间超时，系统核销订单", OrderEventType.CONSUMEBYSYSTEM.toString());

            orderEventDao.save(orderEvent);

        }

    }

    /**
     * 发送标记支付email
     */
    public void sendMarkPayEmail() {

        Date startPayTime = new Date();

        startPayTime = DateUtils.setHours(startPayTime, 0);
        startPayTime = DateUtils.setMinutes(startPayTime, 0);
        startPayTime = DateUtils.setSeconds(startPayTime, 0);
        startPayTime = DateUtils.setMilliseconds(startPayTime, 0);

        startPayTime = DateUtils.addDays(startPayTime, -1);

        List<String> operatorTypes = Arrays.asList(RoleTemplate.SALE_DIRECTOR, RoleTemplate.SALE_USER, RoleTemplate.ADMIN_USER).stream().map(a -> a.toString()).collect(Collectors.toList());

        List<Order> orders = orderDao.list(startPayTime, operatorTypes);


        StringBuilder strings = new StringBuilder();

        orders.stream().forEach(order -> {
            StringBuilder stringBuilder = new StringBuilder();

            stringBuilder.append("<tr>");

            stringBuilder.append("<td>");
            stringBuilder.append(order.getCode());
            stringBuilder.append("</td>");

            stringBuilder.append("<td>");
            stringBuilder.append(order.getAlamoCode());
            stringBuilder.append("</td>");

            stringBuilder.append("<td>");
            stringBuilder.append(DateFormatUtils.format(order.getMarkPayTime()));
            stringBuilder.append("</td>");

            stringBuilder.append("<td>");
            stringBuilder.append(order.getMarkPayOperator());
            stringBuilder.append("</td>");

            stringBuilder.append("<td>");
            stringBuilder.append(new BigDecimal(order.getActualPayPrice()).divide(new BigDecimal(100)));
            stringBuilder.append("</td>");

            stringBuilder.append("</tr>");

            strings.append(stringBuilder.toString());
        });

        Map<String, String> model = new HashMap<>();

        model.put("slot", strings.toString());

        String text = generateEmailText(model);

        mailHandler.sendEmail(financeEmail, "销售标记支付列表", text);


    }

    /*
     * (non-Javadoc)
     * @see com.fita.wechat.service.OrderService#generateCancel(com.fita.entity.order.Order)
     */
    public Map<String, Object> generateCancel(Order order) {

        Supplier supplier = supplierDao.loadByBrand(order.getBrand());

        Map<String, Object> surnameMap = orderDao.getSurname(order.getId());

        if ((supplier == null || supplier.getId() == null)) {
            logger.error("generateCancel occurs error : 查询参数异常, [{}]", JsonUtils.toJson(order));
            throw BusinessException.newInstance("500", "查询参数异常");
        }

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("status", "Available");
        params.put("cancel_type", "Cancel");
        params.put("unique_id", order.getAlamoCode());
        params.put("unique_type", "14");
        params.put("given_name", order.getCustomerName());
        params.put("surname", surnameMap.get("surname"));
        params.put("vendor_code", supplier.getPrefCode());

        logger.info("generateReservation success with result [{}]", JsonUtils.toJson(params));

        return params;
    }

}
